﻿#include "db_api_.h"

int add_record(FIL * f, RECORD * rec)
{
	int res = 0;
	unsigned int br;
	res += f_lseek(f, f_size(f));					if(res)return res;
	res += f_write(f, rec, sizeof(RECORD), &br);	if(res)return res;
	return res;
}

int sync_to(FIL * f, RECORD * fm)
{
	int i;
	int res = FR_OK;
	unsigned int br = sizeof(RECORD);
	RECORD tmp;

	res += f_lseek(f, 0);	if(res)return res;
	while(res == FR_OK && br == sizeof(RECORD))
	{
		res += f_read(f, &tmp, sizeof(RECORD), &br);
		if(res == FR_OK && br == sizeof(RECORD))
		{
			if(tmp.sorthash != fm->sorthash)	continue;
			if(dircmp(tmp.path, fm->path)==0)
			{
				tmp.like = fm->like;
				for(i=0; i<MAXTAG; i++)
				{
					tmp.tag[i] = fm->tag[i];
				}
				if(fm->type & MEDIA_HI_TEXT)
				{
					strcpy(tmp.album,fm->album);
				}
				res += f_lseek(f, f_tell(f) - sizeof(RECORD));	if(res)break;
				res += f_write(f, &tmp, sizeof(RECORD), &br);	if(res)break;
				break;
			}
		}
	}

	return res;
}

int need_sync(RECORD * rec)
{
	if(rec->flag == 1)	//已经删除的记录
		return 0;

	if(rec->like)	//有like信息；
		return 1;

	if(rec->type & (MEDIA_HI_AUDIO|MEDIA_HI_WAVE))		//音乐文件有tag；
		return (rec->tag[0]||rec->tag[1]||rec->tag[2]||rec->tag[3]||rec->tag[4]||rec->tag[5]);

	if(rec->type & MEDIA_HI_TEXT)	//电子书文件，不管有无tag，一定有关联的idx文件；
		return 1;

	return 0;
}

int sync_records(FIL * f_from, FIL * f_to)
{
	int res = FR_OK;
	unsigned int br = sizeof(RECORD);
	RECORD rec;

	res = f_lseek(f_from, 0);	if(res)return res;
	while(hDB->state == 1 && res == FR_OK && br == sizeof(RECORD))
	{
		res += message_pump(hDB->state);
		res += f_read(f_from, &rec, sizeof(RECORD), &br);
		if(res == FR_OK && br == sizeof(RECORD))
		{
			//同步like信息； 同步audio的tag；同步ebook的tag；同步ebook的idx
			if(need_sync(&rec))
			{
				res += sync_to(f_to, &rec);
			}
		}
	}

	return res;
}

int add_root_record(FIL * f, char * path, char * fname)
{
	RECORD rec={0};
	strcpy(rec.path, path);
	name_to_utf8((const unsigned char *)fname, (unsigned char *)rec.fname, MAXUTF8ITEM);
	rec.type = MEDIA_HI_FOLDER;
	rec.sorthash = 0;
	return add_record(f, &rec);
}

int parse_folder(const char * path, const char * fname)
{
	int res = 0;
	RECORD rec={0};

	strcpy(rec.path, path);
	name_to_utf8((const unsigned char *)fname, (unsigned char *)rec.fname, MAXUTF8ITEM);
	rec.type = MEDIA_HI_FOLDER;
	rec.sorthash = 0;//sorthash(fname);//folder的sorthash值填写0；目的是把目录排在最前面

	res += add_record(hDB->f_record_new, &rec);

	return res;
}

int get_audio_info(RECORD * rec)
{
	int res = 0;
	ID3_INFO info = {0};
	int ret = -1;
	
	switch(rec->type & 0x0000ffff)
	{
	case MEDIA_LO_MP3:
	case MEDIA_LO_AAC:
	case MEDIA_LO_WMA:
	case MEDIA_LO_M4A:
		break;

	case MEDIA_LO_FLAC:
		ret = db_flac_parse(rec->path, &info);
		break;

	case MEDIA_LO_APE:
		ret = db_ape_parse(rec->path, &info);
		break;

	case MEDIA_LO_WAV:
	case MEDIA_LO_OGG:
	case MEDIA_LO_AVI:
		break;

	default:
		assert(0);
		break;
	}

	if(ret != 0)
	{
		ret = db_mp3_parse(rec->path, &info);
	}

	switch(ret)
	{
	case 0:	//0==正常解析；
		res += id3_cont_to_utf8(&info.album, (unsigned char *)rec->album, MAXUTF8ITEM-1);
		res += id3_cont_to_utf8(&info.artist, (unsigned char *)rec->artist, MAXUTF8ITEM-1);
		rec->flag = 0;
		break;
	case -1:	//-1=解析出错；
		rec->flag = (unsigned int)-1;
		break;
	case -2:	//-2=no id3 info；
		rec->flag = 0;
		break;
	default:	//others=fs error；
		res = ret;
		rec->flag = 0;
		break;
	}

	return res;
}

void get_text_info(RECORD * rec)
{
	sprintf(rec->album, EBROOT"\\%08d.idx", hDB->ebookSN);
	hDB->ebookSN++;
}

int parse(const char * path, const char * fname)
{
	int res = 0;
	RECORD rec={0};
	int type = file_type(path);
	if(type == 0)return 0;

	strcpy(rec.path, path);
	name_to_utf8((const unsigned char *)fname, (unsigned char *)rec.fname, MAXUTF8ITEM);
	rec.type = type;
	rec.sorthash = sorthash(fname);

	if(type & MEDIA_HI_AUDIO)
	{
		res += get_audio_info(&rec);	if(res)return res;
		if(rec.album[0] == 0)
			strcpy(rec.album, "unknow");
		if(rec.artist[0] == 0)
			strcpy(rec.artist, "unknow");
	}
	else if(type & MEDIA_HI_TEXT)
	{
		get_text_info(&rec);
	}
	res += add_record(hDB->f_record_new, &rec);

	return res;
}

int parse_wave(const char * path, const char * fname)
{
	int res = 0;
	RECORD rec={0};

	strcpy(rec.path, path);
	name_to_utf8((const unsigned char *)fname, (unsigned char *)rec.fname, MAXUTF8ITEM);
	rec.type = MEDIA_HI_WAVE | MEDIA_LO_WAV;
	rec.sorthash = sorthash(fname);

	res += add_record(hDB->f_record_new, &rec);

	return res;
}

int scanfile(char * root, int * nest)
{
	int res = 0;
    DIR dj;         /* Directory object */
    FILINFO fno;    /* File information */
	char path[MAXPATH];

	hDB->cb(-10, (int)root);

	res += f_findfirst(&dj, &fno, root, "*");		if(res)return res;
	
	while(res == FR_OK && fno.fname[0])
	{
		res += message_pump(hDB->state);			if(res)break;if(hDB->state != 1)break;

		strcpy(path, root);
		strcat(path, "\\");
		strcat(path, fno.fname);

		if((fno.fattrib & AM_DIR)
			&&((*nest) < 8)
			&&(0 != strcmp(fno.fname, "."))
			&&(0 != strcmp(fno.fname, ".."))
			&&(0 == is_ignore_dir(path))
			&&(0 != dircmp(path, WAVEROOT)) )
		{
			res += parse_folder(path, fno.fname);	if(res)break;

			(*nest) ++;
			res += scanfile(path, nest);			if(res)break;
			(*nest) --;
		}
		else if((fno.fattrib & AM_ARC) && !(fno.fattrib & AM_HID) && !(fno.fattrib & AM_SYS))
		{
			++hDB->count;
			//hDB->cb(-11, hDB->count);
			{
				int persent = hDB->count * 98 / 10240;
				if(persent > 98)	persent = 98;
				hDB->cb(-555, persent);
			}
			res += parse(path, fno.fname);			if(res)break;
		}

		res += f_findnext(&dj, &fno);				if(res)break;
    }

    res += f_closedir(&dj);
	hDB->cb(-12, (int)root);
	return res;
}

int scanwave(char * root)
{
	int res = 0;
    DIR dj;         /* Directory object */
    FILINFO fno;    /* File information */
	char path[MAXPATH];

	res += f_findfirst(&dj, &fno, root, "*.wav");	if(res)return 0;
	
	while(res == FR_OK && fno.fname[0])
	{
		res += message_pump(hDB->state);			if(res)break;if(hDB->state != 1)break;

		strcpy(path, root);
		strcat(path, "\\");
		strcat(path, fno.fname);

		if(fno.fattrib & AM_ARC)
		{
			res += parse_wave(path, fno.fname);		if(res)break;
		}

		res += f_findnext(&dj, &fno);				if(res)break;
    }

    res += f_closedir(&dj);
	return res;
}

int records_sort(FIL * f_sort)
{
	int res = 0;
	int i,j,k;
	unsigned int br;
	RECORD rec[2];
	RECORD * src = &rec[0];
	RECORD * des = &rec[1];
	int rec_cnt = (int)f_size(f_sort);
	assert(rec_cnt % sizeof(RECORD) == 0);
	rec_cnt /= sizeof(RECORD);

	for(i=0; i<rec_cnt-1; i++)
	{
		res += message_pump(hDB->state);						if(res)break;if(hDB->state != 2)break;

		k = i;
		res += f_lseek(f_sort, i*sizeof(RECORD));				if(res)break;
		res += f_read(f_sort, src, sizeof(RECORD), &br);		if(res)break;
		for(j=i+1; j<rec_cnt; j++)
		{
			res += f_lseek(f_sort, j*sizeof(RECORD));			if(res)break;
			res += f_read(f_sort, des, sizeof(RECORD), &br);	if(res)break;

			if(src->sorthash > des->sorthash)
			{
				RECORD * tmp;
				tmp = src;	src = des;	des = tmp;
				k = j;
			}
		}
		if(k != i)
		{
			res += f_lseek(f_sort, i*sizeof(RECORD));			if(res)break;
			res += f_read(f_sort, des, sizeof(RECORD), &br);	if(res)break;

			res += f_lseek(f_sort, i*sizeof(RECORD));			if(res)break;
			res += f_write(f_sort, src, sizeof(RECORD), &br);	if(res)break;

			res += f_lseek(f_sort, k*sizeof(RECORD));			if(res)break;
			res += f_write(f_sort, des, sizeof(RECORD), &br);	if(res)break;
		}
	}

	return res;
}

int records_scan(void)
{
	int res = 0;
	int nest = 0;

	res += add_root_record(hDB->f_record_new, SDROOT, "");			if(res)return res;if(hDB->state != 1)return res;
	res += add_root_record(hDB->f_record_new, WAVEROOT, "record");	if(res)return res;if(hDB->state != 1)return res;
	res += scanfile(SDROOT, &nest);									if(res)return res;if(hDB->state != 1)return res;
	res += scanwave(WAVEROOT);										if(res)return res;if(hDB->state != 1)return res;

	return res;
}